﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BlackBBS.Models.Data;
using Sider;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Runtime.Serialization;

namespace BlackBBS.Infrastructure.Repository
{
    public class XMLRepository<T> : RepositoryBase, IDisposable, IRepository<T> where T : IRepositoryEntity
    {
        private List<T> _data = null;

        public string Filename { get; set; }

        public XMLRepository(string filename)
        {
            try
            {
                this.Filename = filename;
                this.LoadXML();
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("Error Loading XML File {0}; [{1}]", this.Filename, ex.Message));
                this.Close();
                System.IO.File.Delete(this.Filename);
                this.LoadXML();
                Console.WriteLine("Corrupted XML File. Deleted and Recreated");
            }
        }

        public void Open()
        {
            // do nothing for this implementation
        }
        public void Close()
        {
            // do nothing for this implementation
        }
        public long Count()
        {
            var result = this._data.Count();
            return result;
        }
        public long NextId()
        {
            var result = this.Count() + 1;
            return result;
        }
        public bool Delete(long key)
        {
            try
            {
                this._data = this._data.Where(x => x.Id != key).ToList();
                this.SaveXML();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
        public T Get(long key)
        {
            var data = this._data.Where(x => x.Id.Equals(key)).FirstOrDefault();
            if (data == null)
            {
                this.LoadXML();
                data = this._data.Where(x => x.Id.Equals(key)).FirstOrDefault();
            }
            return data == null ? default(T) : data;
        }

        public IEnumerable<T> GetAll()
        {
            this.LoadXML();
            return this._data;             
        }
        public void Save(T entity)
        {
            int index = this._data.FindIndex(x => x.Id.Equals(entity.Id));
            if (index < 0 || entity.Id == 0)
            {
                if (entity.Id == 0)
                {
                    entity.Id = this._data.Count() + 1;
                }
                this._data.Add(entity);
            }
            else
            {
                this._data[index] = entity;
            }
            this.SaveXML();
        }
        public void Dispose()
        {
            // do nothing for this implementation
        }

        void SaveXML()
        {
            lock (this)
            {
                var writer = new FileStream(this.Filename, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
                var ser = new DataContractSerializer(typeof(List<T>));
                ser.WriteObject(writer, this._data);
                writer.Close();
                writer.Dispose();
            }
        }

        void LoadXML()
        {
            lock (this)
            {
                using (var fs = new FileStream(this.Filename, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read))
                {
                    if (fs.Length == 0)
                    {
                        this._data = new List<T>();
                    }
                    else
                    {
                        var reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
                        var ser = new DataContractSerializer(typeof(List<T>));
                        this._data = (List<T>)ser.ReadObject(reader, true);
                        reader.Close();
                        fs.Close();
                    }
                }
            }
        }

    }

}
